package cc.shacocloud.mirage.loader;

import cc.shacocloud.mirage.loader.jar.JarFile;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.Manifest;

/**
 * {@link MirageClassLoader} 类加载器耗时统计
 *
 * @author 思追(shaco)
 */
public class MirageTimeClassLoader extends MirageClassLoader {
    
    public MirageTimeClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }
    
    public MirageTimeClassLoader(boolean exploded, URL[] urls, ClassLoader parent) {
        super(exploded, urls, parent);
    }
    
    public MirageTimeClassLoader(boolean exploded, JarFile jarFile, URL[] urls, ClassLoader parent) {
        super(exploded, jarFile, urls, parent);
    }
    
    
    @Override
    public URL findResource(String name) {
        return timer("findResource :" + name, () -> super.findResource(name));
    }
    
    @Override
    public Enumeration<URL> findResources(String name) throws IOException {
        return timer("findResources :" + name, () -> super.findResources(name));
    }
    
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        return timer("loadClass :" + name, () -> super.loadClass(name, resolve));
    }
    
    @Override
    protected void definePackageIfNecessary(@NotNull String className) {
        timer("definePackageIfNecessary :" + className, () -> {
            super.definePackageIfNecessary(className);
            return null;
        });
    }
    
    @Override
    protected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException {
        return timer("definePackage1 :" + name, () -> super.definePackage(name, man, url));
    }
    
    @Override
    protected Package definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) throws IllegalArgumentException {
        return timer("definePackage2 :" + name, () -> super.definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase));
    }
    
    @SneakyThrows
    private <R> R timer(@NotNull String name, @NotNull Supplier<R> supplier) {
        long start = System.currentTimeMillis();
        
        try {
            return supplier.get();
        } finally {
            long hs = System.currentTimeMillis() - start;
            
            if (hs > 10) {
                System.err.printf("MirageTimeClassLoader %s 执行耗时 %s ms%n", name, hs);
            }
        }
    }
    
    @FunctionalInterface
    interface Supplier<T> {
        
        
        T get() throws Exception;
    }
    
    
}
